﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace TempHumidityMonitor {
    public partial class Form1 : Form {
        private ModbusHelper _modbusHelper;
        private System.Windows.Forms.Timer _readTimer;
        private AppConfig _appConfig; // 存储当前配置
        private const byte SLAVE_ID = 1; // Modbus从站地址
        
        // --- 新增：用于报警管理 ---
        private string _lastAlarmMessage = ""; // 记录上一次的报警内容，用于去重
        private DateTime _lastAlarmTime = DateTime.MinValue;

        public Form1() {
            InitializeComponent();
            InitializeUI();
            SetupTimer();
        }

        private void InitializeUI() {
            // 设置图表
            chartData.Series.Clear();
            var seriesTemp = chartData.Series.Add("温度");
            seriesTemp.ChartType = SeriesChartType.Line;
            seriesTemp.Color = Color.Red;

            var seriesHumi = chartData.Series.Add("湿度");
            seriesHumi.ChartType = SeriesChartType.Line;
            seriesHumi.Color = Color.Blue;

            var chartArea = chartData.ChartAreas[0];

            chartArea.AxisX.LabelStyle.Format = "HH:mm:ss";
            chartArea.AxisX.MajorGrid.Interval = 3;
            chartArea.AxisX.MajorGrid.IntervalType = DateTimeIntervalType.Seconds;
            chartArea.AxisX.LabelStyle.Interval = 3;
            chartArea.AxisX.LabelStyle.IntervalType = DateTimeIntervalType.Seconds;

            chartArea.AxisY.Minimum = 0;
            chartArea.AxisY.Maximum = 100;
            chartArea.AxisY2.Enabled = AxisEnabled.True;
            chartArea.AxisY2.Minimum = 0;
            chartArea.AxisY2.Maximum = 100;

            //chartArea.AxisX.ScaleView.Zoomable = true;

            // 初始化状态标签
            labelStatus.Text = "未连接";
            labelStatus.ForeColor = Color.Red;

            // 初始缩放大小设置为60秒（例如），可以根据需要调整
            //chartArea.AxisX.ScaleView.Size = 10;
            //chartArea.AxisX.ScaleView.SizeType = DateTimeIntervalType.Seconds;

        }

        private void SetupTimer() {
            _readTimer = new System.Windows.Forms.Timer();
            _readTimer.Interval = 2000; // 每2秒读取一次
            _readTimer.Tick += ReadTimer_Tick;
        }

        private async void ReadTimer_Tick(object sender, EventArgs e) {
            if (_modbusHelper == null || !_modbusHelper.IsConnected)
                return;

            try {
                // 使用 Task.Run 并传入取消令牌
                var result = await Task.Run(() => _modbusHelper.ReadData(SLAVE_ID));

                if (result.HasValue) {
                    float temp = result.Value.temperature;
                    float humi = result.Value.humidity;

                    // 更新UI
                    UpdateDisplay(temp, humi);
                    AddToChart(DateTime.Now, temp, humi);
                    DatabaseHelper.SaveData(temp, humi);
                    CheckAlarm(temp, humi);
                }
                else {
                    SetStatus("读取数据失败", Color.Orange);
                }
            }
            catch (Exception ex) {
                this.Invoke((MethodInvoker)delegate {
                    SetStatus($"读取异常: {ex.Message}", Color.Red);
                });
            }
        }

        private void UpdateDisplay(float temp, float humi) {
            labelTemp.Text = $"{temp:F1} °C";
            labelHumi.Text = $"{humi:F1} %";
            SetStatus("连接正常", Color.Green);
        }

        private void AddToChart(DateTime time, float temp, float humi) {
            // 添加数据点
            chartData.Series["温度"].Points.AddXY(time, temp);
            chartData.Series["湿度"].Points.AddXY(time, humi);

            // 限制显示的数据点数量，防止图表过长
            const int maxPoints = 10;
            while (chartData.Series["温度"].Points.Count > maxPoints) {
                chartData.Series["温度"].Points.RemoveAt(0);
                chartData.Series["湿度"].Points.RemoveAt(0);
            }

            // 自动调整 X 轴范围
            var chartArea = chartData.ChartAreas[0];
            if (chartData.Series["温度"].Points.Count > 0) {
                DateTime minTime = DateTime.FromOADate(chartData.Series["温度"].Points[0].XValue);
                DateTime maxTime = time;

                chartArea.AxisX.Minimum = minTime.ToOADate();
                chartArea.AxisX.Maximum = maxTime.ToOADate();
            }

            chartData.Invalidate();
        }

        /// <summary>
        /// 检查温湿度是否超出阈值，并更新UI和报警列表
        /// </summary>
        private void CheckAlarm(float temp, float humi) {
            // 用于收集所有激活的报警
            List<string> activeAlarms = new List<string>();
            Color statusColor = Color.Green; // 默认正常颜色

            // 获取当前阈值
            float highTemp = (float)numericUpDownHighTemp.Value;
            float lowTemp = (float)numericUpDownLowTemp.Value;
            float highHumi = (float)numericUpDownHighHumi.Value;
            float lowHumi = (float)numericUpDownLowHumi.Value;

            // 检查温度
            if (temp > highTemp) {
                activeAlarms.Add($"🔥 高温 {temp:F1}°C");
                if (statusColor == Color.Green)
                    statusColor = Color.Red; // 第一个非正常报警决定主色调
            }
            else if (temp < lowTemp) {
                activeAlarms.Add($"❄️ 低温 {temp:F1}°C");
                if (statusColor == Color.Green)
                    statusColor = Color.Blue;
            }

            // 检查湿度
            if (humi > highHumi) {
                activeAlarms.Add($"💧 高湿 {humi:F1}%");
                if (statusColor == Color.Green)
                    statusColor = Color.Orange;
            }
            else if (humi < lowHumi) {
                activeAlarms.Add($"🌫️ 低湿 {humi:F1}%");
                if (statusColor == Color.Green)
                    statusColor = Color.Purple;
            }

            // --- 根据结果更新UI ---
            if (activeAlarms.Count > 0) {
                // 将所有报警信息用分号连接
                string combinedMessage = string.Join("; ", activeAlarms);

                // 更新状态栏
                UpdateStatusStrip(combinedMessage, statusColor);

                // 记录到报警列表（避免重复）
                string logKey = string.Join("|", activeAlarms); // 用管道符连接作为唯一键
                if (_lastAlarmMessage != logKey || (DateTime.Now - _lastAlarmTime).TotalSeconds > 60) {
                    LogAlarm(combinedMessage);
                    _lastAlarmMessage = logKey;
                    _lastAlarmTime = DateTime.Now;

                    // 🔊 可选：播放提示音
                    if ((DateTime.Now - _lastAlarmTime).TotalSeconds > 300) {
                        System.Media.SystemSounds.Exclamation.Play();
                    }
                }
            }
            else {
                // 所有指标正常
                UpdateStatusStrip("正常", Color.Green);
                _lastAlarmMessage = "";
            }
        }

        /// <summary>
        /// 更新底部状态栏
        /// </summary>
        /// <param name="message">要显示的消息</param>
        /// <param name="color">文本颜色</param>
        private void UpdateStatusStrip(string message, Color color)
        {
            // ✅ 使用 Form (this) 来检查和调用
            if (this.InvokeRequired)
            {
                // 如果在工作线程，需要通过 Invoke 切换到UI线程
                this.Invoke((MethodInvoker)delegate {
                    toolStripStatusLabel1.Text = message;
                    toolStripStatusLabel1.ForeColor = color;
                });
            }
            else
            {
                // 如果已经在UI线程，直接更新
                toolStripStatusLabel1.Text = message;
                toolStripStatusLabel1.ForeColor = color;
            }
        }

        /// <summary>
        /// 记录报警到ListBox
        /// </summary>
        /// <param name="message">报警消息</param>
        private void LogAlarm(string message) {
            string logEntry = $"[{DateTime.Now:HH:mm:ss}] {message}";

            // ✅ 最佳实践：用 'this' 检查，用 listBoxAlarms.Invoke 执行
            if (this.InvokeRequired) {
                // 使用 listBoxAlarms 的 Invoke 方法将委托封送到UI线程
                listBoxAlarms.Invoke((MethodInvoker)delegate {
                    listBoxAlarms.Items.Add(logEntry);
                    listBoxAlarms.TopIndex = listBoxAlarms.Items.Count - 1;
                });
            }
            else {
                // 直接在UI线程上操作
                listBoxAlarms.Items.Add(logEntry);
                listBoxAlarms.TopIndex = listBoxAlarms.Items.Count - 1;
            }
        }

        private void SetStatus(string text, Color color) {
            labelStatus.Text = text;
            labelStatus.ForeColor = color;
        }

        // --- UI事件处理 ---
        private void btnConnect_Click(object sender, EventArgs e) {
            if (_modbusHelper?.IsConnected == true) {
                _readTimer.Stop();

                _modbusHelper?.Dispose();
                _modbusHelper = null;

                btnConnect.Text = "连接";
                SetStatus("已断开", Color.Red);
                return;
            }

            string portName = comboBoxPort.Text;
            if (string.IsNullOrEmpty(portName)) {
                MessageBox.Show("请选择串口号！");
                return;
            }

            int baudRate = int.Parse(comboBoxBaudRate.Text);

            _modbusHelper = new ModbusHelper();
            if (_modbusHelper.Connect(portName, baudRate)) {
                _readTimer.Start();
                btnConnect.Text = "断开";
                SetStatus("连接成功", Color.Green);
            }
            else {
                MessageBox.Show("无法打开串口，请检查设备或端口设置。");
                SetStatus("连接失败", Color.Red);
            }
        }

        private void btnLoadHistory_Click(object sender, EventArgs e) {
            DataTable data = DatabaseHelper.GetAllData();
            dataGridViewHistory.DataSource = data;
        }

        private void Form1_Load(object sender, EventArgs e) {

            // --- 加载配置 ---
            _appConfig = JsonHelper.LoadConfig();

            // 自动填充串口号
            string[] ports = System.IO.Ports.SerialPort.GetPortNames();
            comboBoxPort.Items.AddRange(ports);
            if (!string.IsNullOrEmpty(_appConfig.PortName) && ports.Contains(_appConfig.PortName))
            {
                comboBoxPort.SelectedItem = _appConfig.PortName;
            }
            else if (ports.Length > 0)
            {
                comboBoxPort.SelectedIndex = 0; // 默认第一个
            }

            // 设置默认波特率
            comboBoxBaudRate.Items.AddRange(new object[] { "9600", "19200", "38400", "57600", "115200" });
            if (_appConfig.BaudRate.ToString() == comboBoxBaudRate.Items.Cast<string>().FirstOrDefault(x => x == _appConfig.BaudRate.ToString()))
            {
                comboBoxBaudRate.SelectedItem = _appConfig.BaudRate.ToString();
            }
            else
            {
                comboBoxBaudRate.SelectedItem = "115200"; // 默认
            }

            // 设置报警阈值
            numericUpDownHighTemp.Value = (decimal)_appConfig.HighTemp;
            numericUpDownLowTemp.Value = (decimal)_appConfig.LowTemp;
            numericUpDownHighHumi.Value = (decimal)_appConfig.HighHumi;
            numericUpDownLowHumi.Value = (decimal)_appConfig.LowHumi;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            _readTimer?.Stop();

            // 直接调用 Disconnect，它会安全地清理所有资源
            _modbusHelper?.Dispose();
            _modbusHelper = null;

            // --- 保存当前配置 ---
            _appConfig.PortName = comboBoxPort.Text;
            _appConfig.BaudRate = int.Parse(comboBoxBaudRate.Text);
            _appConfig.HighTemp = (float)numericUpDownHighTemp.Value;
            _appConfig.LowTemp = (float)numericUpDownLowTemp.Value;
            _appConfig.HighHumi = (float)numericUpDownHighHumi.Value;
            _appConfig.LowHumi = (float)numericUpDownLowHumi.Value;

            JsonHelper.SaveConfig(_appConfig);
        }

        private void btnExport_Click(object sender, EventArgs e) {
            // ✅ 直接从数据库获取所有数据，不依赖 DataGridView 的 DataSource
            DataTable allData = DatabaseHelper.GetAllData();

            if (allData == null || allData.Rows.Count == 0) {
                MessageBox.Show("数据库中没有历史数据可导出。", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            using (SaveFileDialog sfd = new SaveFileDialog()) {
                sfd.Filter = "Excel文件|*.xlsx";
                sfd.Title = "导出历史数据";
                if (sfd.ShowDialog() == DialogResult.OK) {
                    ExportToExcel(allData, sfd.FileName);
                }
            }
        }

        // 此方法现在只接收一个 DataTable，不再需要从 DataGridView 取数据
        private void ExportToExcel(DataTable dt, string filePath) {
            try {
                NPOI.XSSF.UserModel.XSSFWorkbook workbook = new NPOI.XSSF.UserModel.XSSFWorkbook();
                NPOI.SS.UserModel.ISheet sheet = workbook.CreateSheet("历史数据");

                // 创建表头
                NPOI.SS.UserModel.IRow headerRow = sheet.CreateRow(0);
                for (int i = 0; i < dt.Columns.Count; i++) {
                    headerRow.CreateCell(i).SetCellValue(dt.Columns[i].ColumnName);
                }

                // 填充数据
                for (int i = 0; i < dt.Rows.Count; i++) {
                    NPOI.SS.UserModel.IRow row = sheet.CreateRow(i + 1);
                    for (int j = 0; j < dt.Columns.Count; j++) {
                        row.CreateCell(j).SetCellValue(dt.Rows[i][j]?.ToString());
                    }
                }

                // 自动调整列宽
                for (int i = 0; i < dt.Columns.Count; i++) {
                    sheet.AutoSizeColumn(i);
                }

                using (System.IO.FileStream fs = new System.IO.FileStream(filePath, System.IO.FileMode.Create, System.IO.FileAccess.Write)) {
                    workbook.Write(fs);
                }

                MessageBox.Show("导出成功！");
            }
            catch (Exception ex) {
                MessageBox.Show($"导出失败: {ex.Message}");
            }
        }

    }
}